//
//  main.m
//  thp-server-lib-test
//
//  Created by guolihui on 16/1/25.
//  Copyright © 2016年 tiandiyou. All rights reserved.
//

#include <iostream>
#include "ThmEventableStateMachine.h"
#include <string>
#include <assert.h>
#include <tuple>
#include "ThmDoubleCardEventableStateMachine.h"

std::string thmStateToString(EN_ThmStateType stateType){
#define CASE(item) case item: return #item; break;
    switch (stateType) {
            CASE(ThmStateType_WaitOpen)
            CASE(ThmStateType_Preblind)
            CASE(ThmStateType_SmallBlind)
            CASE(ThmStateType_BigBlind)
            CASE(ThmStateType_DispatchCards)
            CASE(ThmStateType_TurnPlayer)
            CASE(ThmStateType_PlayerAct)
            CASE(ThmStateType_CollectPot)
            CASE(ThmStateType_RoundEnd)
            CASE(ThmStateType_Showdown)
            CASE(ThmStateType_NewRound)
            CASE(ThmStateType_DispatchPot)
            CASE(ThmStateType_PlayerFinalChip)
            CASE(ThmStateType_InningEnd)
            CASE(ThmStateType_DoubleCards_DispatchPot)
            CASE(ThmStateType_DoubleCards_PublicCard)
        default:
            break;
    }
    return "<Unknown>";
}


class LogThmEventableStateMachineListener : public ThmEventableStateMachineListener {
    virtual void ThmEventableStateMachine_onInningStart(){
        std::cout << "onInningStart >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onPreblindActs(const ThmEventableStateMachine::PlayerActionInfo* arrActInfos, int count){
        std::cout << "onPreblindActs >" << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerSmallBlindAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo) {
        std::cout << "onPlayerSmallBlindAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerBigBlindAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo){
        std::cout << "onPlayerBigBlindAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onBoardDispatchCards(const int arrPlayerCards[][2], int count){
        std::cout << "onBoardDispatchCards >" << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerTurn(const BoardActionsUtils::TurnPlayerInfo& turnInfo){
        std::cout << "onPlayerTurn >" << turnInfo.nPos << "[canRaise:" <<  turnInfo.bCanRaise << ", minRaise:"
        << turnInfo.llMinRaiseStake << ", callStake:" << turnInfo.llCallStake << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo){
        std::cout << "onPlayerAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onCollectPot(int roundIndex,
                                                       const BoardPotCollectAlgo::BoardRoundPotResult& potResult,
                                                       const BoardPotCollectAlgo::BoardRoundPotResult& potIncInfo
                                                       ){
        
        std::cout << "onCollectPot >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onRoundEnd(int roundIndex){
        std::cout << "onRoundEnd >" << roundIndex << std::endl;
    }
    virtual void ThmEventableStateMachine_onShowdown(const int* arrPlayers, int count){
        std::cout << "onShowdown >" << count << std::endl;
    }
    virtual void ThmEventableStateMachine_onNewRound(int roundIndex){
        std::cout << "onNewRound >" << roundIndex << std::endl;
    }
    virtual void ThmEventableStateMachine_onDispatchPot(const BoardPotCollectAlgo::BoardRoundPotResult& winData){
        std::cout << "onDispatchPot >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onPlayerFinalChip (const int64_t* arrPlayerChips, int count){
        
        std::cout << "onPlayerFinalChip >" << std::endl;
        for (int i = 0; i < count; ++i){
            std::cout << "       " << arrPlayerChips[i] << std::endl;
        }
    }
    virtual void ThmEventableStateMachine_onInningEnd(){
        std::cout << "onInningEnd >" << std::endl;
    }
    
    // ’‚∏ˆ◊¥Ã¨ «‘⁄…œ ˆªÿµ˜÷Æ∫Û∑µªÿµƒ
    virtual void ThmEventableStateMachine_onStateChanged(EN_ThmStateType newState, EN_ThmStateType oldState) {
    }
    
    // ÕÊº“¿Îø™ ’‚∏ˆ≤ª «“ª∏ˆ◊¥Ã¨÷ª «“ª∏ˆ ¬º˛Õ®÷™
    virtual void ThmEventableStateMachine_onPlayerLeave(int nPos){
        std::cout << "onPlayerLeave >" << nPos << std::endl;
    }
    
    virtual void other_InningOver(bool bover = true){
        
        std::cout << "InningOver >" << bover << std::endl;
    }
};


class LogThmDoubleEventableStateMachineListener : public ThmDoubleCardEventableStateMachineListener {
    virtual void ThmEventableStateMachine_onInningStart(){
        std::cout << "onInningStart >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onPreblindActs(const ThmEventableStateMachine::PlayerActionInfo* arrActInfos, int count){
        std::cout << "onPreblindActs >" << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerSmallBlindAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo) {
        std::cout << "onPlayerSmallBlindAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerBigBlindAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo){
        std::cout << "onPlayerBigBlindAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onBoardDispatchCards(const int arrPlayerCards[][2], int count){
        std::cout << "onBoardDispatchCards >" << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerTurn(const BoardActionsUtils::TurnPlayerInfo& turnInfo){
        std::cout << "onPlayerTurn >" << turnInfo.nPos << "[canRaise:" <<  turnInfo.bCanRaise << ", minRaise:"
        << turnInfo.llMinRaiseStake << ", callStake:" << turnInfo.llCallStake << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onPlayerAct(const ThmEventableStateMachine::PlayerActionInfo& actInfo){
        std::cout << "onPlayerAct >" << actInfo.m_actInfo.nPos << std::endl;
        
    }
    virtual void ThmEventableStateMachine_onCollectPot(int roundIndex,
                                                       const BoardPotCollectAlgo::BoardRoundPotResult& potResult,
                                                       const BoardPotCollectAlgo::BoardRoundPotResult& potIncInfo
                                                       ){
        
        std::cout << "onCollectPot >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onRoundEnd(int roundIndex){
        std::cout << "onRoundEnd >" << roundIndex << std::endl;
    }
    virtual void ThmEventableStateMachine_onShowdown(const int* arrPlayers, int count){
        std::cout << "onShowdown >" << count << std::endl;
    }
    virtual void ThmEventableStateMachine_onNewRound(int roundIndex){
        std::cout << "onNewRound >" << roundIndex << std::endl;
    }
    virtual void ThmEventableStateMachine_onDispatchPot(const BoardPotCollectAlgo::BoardRoundPotResult& winData){
        std::cout << "onDispatchPot >" << std::endl;
    }
    virtual void ThmEventableStateMachine_onPlayerFinalChip (const int64_t* arrPlayerChips, int count){
        
        std::cout << "onPlayerFinalChip >" << std::endl;
        for (int i = 0; i < count; ++i){
            std::cout << "       " << arrPlayerChips[i] << std::endl;
        }
    }
    virtual void ThmEventableStateMachine_onInningEnd(){
        std::cout << "onInningEnd >" << std::endl;
    }
    
    // ’‚∏ˆ◊¥Ã¨ «‘⁄…œ ˆªÿµ˜÷Æ∫Û∑µªÿµƒ
    virtual void ThmEventableStateMachine_onStateChanged(EN_ThmStateType newState, EN_ThmStateType oldState) {
    }
    
    // ÕÊº“¿Îø™ ’‚∏ˆ≤ª «“ª∏ˆ◊¥Ã¨÷ª «“ª∏ˆ ¬º˛Õ®÷™
    virtual void ThmEventableStateMachine_onPlayerLeave(int nPos){
        std::cout << "onPlayerLeave >" << nPos << std::endl;
    }
    
    virtual void other_InningOver(bool bover = true){
        
        std::cout << "InningOver >" << bover << std::endl;
    }
    
    
    virtual void ThmEventableStateMachine_onPublicCardRound_DoubleCards(int roundIndex) {
        
    }
    virtual void ThmEventableStateMachine_onDispatchPot_DoubleCards(BoardPotCollectAlgo::BoardRoundPotResult& winData2){
        
    }
};


class TestCaseManager {
public:
    static TestCaseManager* getInstance(){
        static TestCaseManager s_manager;
        return &s_manager;
    }
    
    void addTestItemResult(const std::string& testName,
                           const std::string& funcName,
                           bool result){
        m_testResult.push_back(std::tuple<std::string, std::string, bool>(testName, funcName, result));
    }
    
    void outputTestResult(){
        std::cout << std::endl;
        std::cout << "---------------------- test result ---------------------" << std::endl;
        
        int testTotalResultCount = 0;
        int testPassedCount = 0;
        for (const std::tuple<std::string, std::string, bool>& item : m_testResult){
            testTotalResultCount++;
            if (std::get<2>(item))
                testPassedCount++;
        }
        
        std::cout << "                         " << ((testPassedCount == testTotalResultCount) ? "    通过   " : "!!!失败")
        << "(" << testPassedCount << "/" << testTotalResultCount << ")" <<  std::endl;
        
        
        for (const std::tuple<std::string, std::string, bool>& item : m_testResult){
            bool bPassed = std::get<2>(item);
            std::cout << "       " << (bPassed ? "     通过" : "!!! 失败") << "    " << std::get<0>(item) << ",  " << std::get<1>(item) << std::endl;
        }
        
        
        std::cout << "--------------------------------------------------------" << std::endl;
    }
private:
    std::vector<std::tuple<std::string, std::string, bool> > m_testResult;
};

bool testInvalidRaiseToCall();
bool testAllinLeavePlayer();
bool testDoublePlayerLeave();
bool testInvalidRaiseToCall_TurnInfo();
bool testOverflowRaiseAndLeave();
bool testDivideEquallyByPlayerChip();
bool testDispatchPotAlgo();
bool testStandAndInningEndDispatchPotAlgo();
bool testPfWithPbRaise();
bool testRoundCallStake();

#define DEF_TEST(testFun, name) \
    {\
        std::cout << std::endl << "-------------------------- test .... " << name << #testFun << std::endl;\
        bool ok = testFun; \
        TestCaseManager::getInstance()->addTestItemResult(name, #testFun, ok);\
        std::cout << " >>>>> " << (ok ? "  passed " : "ERR!! ") << "测试" << #testFun  << " " << name << std::endl;\
        assert(ok);\
    }

int main(int argc, const char * argv[]) {
    //
    DEF_TEST(testRoundCallStake(), "牌圈的跟注值");
    DEF_TEST(testPfWithPbRaise(), "翻牌前加注(带前注)");
    DEF_TEST(testStandAndInningEndDispatchPotAlgo(), "玩家立即站起，然后分彩池逻辑");
    DEF_TEST(testDispatchPotAlgo(), "测试彩池计算逻辑");
    DEF_TEST(testDivideEquallyByPlayerChip(), "某个彩池根据玩家筹码划分");
    DEF_TEST(testOverflowRaiseAndLeave(), "溢出加注然后离开，多出筹码应该归还");
    DEF_TEST(testInvalidRaiseToCall_TurnInfo(), "无效加注轮到状态");
    DEF_TEST(testInvalidRaiseToCall(), "无效加注");
    DEF_TEST(testAllinLeavePlayer(), "双人Allin离开筹码");
    DEF_TEST(testDoublePlayerLeave(), "双人离开筹码");
    
    TestCaseManager::getInstance()->outputTestResult();
    return 0;
}


#define TEST_EXPR(expr) \
    if (expr){} else {std::cout << " >>>> !!! test fail expr " << #expr << std::endl; assert(false); return false;}
#define TEST_EQUAL(firstExpr, secondExpr) \
    {\
        auto __gh_temp_value1 = (firstExpr);\
        auto __gh_temp_value2 = (secondExpr);\
        if (__gh_temp_value1 == __gh_temp_value2){\
            \
        }else{\
            std::cout << " >>>> !!! test fail expr " << #firstExpr << "=" << __gh_temp_value1 << ", " << #secondExpr << " = " << __gh_temp_value2 << std::endl;\
            assert(false);\
            return false;\
        }\
    }

bool testRoundCallStake() {
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[2] = {1, 1};
        parser.init(1, 2, 0, arrPlayerChips, 2);
        TEST_EQUAL(parser.getCurRoundCallStake(), 1);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[2] = {1, 2};
        parser.init(1, 2, 0, arrPlayerChips, 2);
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[3] = {1, 4, 45};
        parser.init(1, 2, 0, arrPlayerChips, 3);
        TEST_EXPR(parser.safeParsePlayerAct(2, ACT_RAISE, 4));
        TEST_EQUAL(parser.getCurRoundCallStake(), 4);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[4] = {1, 4, 45, 99};
        parser.init(1, 2, 0, arrPlayerChips, 4);
        TEST_EXPR(parser.safeParsePlayerAct(2, ACT_RAISE, 40));
        TEST_EXPR(parser.safeParsePlayerAct(3, ACT_FOLD, 0));
        TEST_EQUAL(parser.getCurRoundCallStake(), 40);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[3] = {100, 1000, 45};
        parser.init(1, 2, 0, arrPlayerChips, 3);
        TEST_EXPR(parser.safeParsePlayerAct(2, ACT_RAISE, 40));
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_RAISE, 90));
        TEST_EQUAL(parser.getCurRoundCallStake(), 91);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[3] = {200, 1000, 45};
        parser.init(1, 2, 10, arrPlayerChips, 3);
        TEST_EXPR(parser.safeParsePlayerAct(2, ACT_RAISE, 20));
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_RAISE, 90));
        TEST_EQUAL(parser.getCurRoundCallStake(), 101);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[2] = {20, 20};
        parser.init(1, 2, 0, arrPlayerChips, 2);
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_CHECK, 0));
        TEST_EXPR(parser.safeParseNewRound());
        TEST_EQUAL(parser.getCurRoundCallStake(), 0);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[2] = {3, 3};
        parser.init(1, 2, 0, arrPlayerChips, 2);
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_CHECK, 0));
        TEST_EXPR(parser.safeParseNewRound());
        TEST_EQUAL(parser.getCurRoundCallStake(), 0);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_RAISE, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 1);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 1);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[2] = {9, 3};
        parser.init(1, 2, 0, arrPlayerChips, 2);
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_CHECK, 0));
        TEST_EXPR(parser.safeParseNewRound());
        TEST_EQUAL(parser.getCurRoundCallStake(), 0);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_RAISE, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 1);
        BoardActionsUtils::TurnPlayerInfo turnInfo;
        parser.getCurTurnPlayerInfo(&turnInfo);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 1);
    }
    {
        BoardActionsUtils::BoardActionStepParser parser;
        int64_t arrPlayerChips[3] = {3, 9, 8};
        parser.init(1, 2, 0, arrPlayerChips, 3);
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(2, ACT_CALL, 2));
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_CALL, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_CHECK, 0));
        TEST_EXPR(parser.safeParseNewRound());
        TEST_EQUAL(parser.getCurRoundCallStake(), 0);
        TEST_EXPR(parser.safeParsePlayerAct(0, ACT_RAISE, 1));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
        BoardActionsUtils::TurnPlayerInfo turnInfo;
        parser.getCurTurnPlayerInfo(&turnInfo);
        TEST_EXPR(parser.safeParsePlayerAct(1, ACT_CALL, 2));
        TEST_EQUAL(parser.getCurRoundCallStake(), 2);
    }
    return true;
}
bool testPfWithPbRaise() {
    {
        
        ThmDoubleCardEventableStateMachine machine;
        LogThmDoubleEventableStateMachineListener logListener;
        machine.setDoubleCardStmListener(&logListener);
        
        int64_t llSbChip = 10;
        int64_t llBbChip = 20;
        int64_t llPreblindChip = 20;
        
        int publicCards[5] = {0,1,2,3,4};
        enum { nPlayerCount = 2 };
        int64_t arrPlayerChips[nPlayerCount] = {2000, 2000};
        int arrPlayerHoleCards[nPlayerCount][3] = {
            {0, 5,6},
            {1, 7,8},
        };
        
        machine.start(llSbChip, llBbChip, llPreblindChip,
                      publicCards,
                      arrPlayerChips,
                      arrPlayerHoleCards,
                      nPlayerCount);
        
        while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
            machine.gotoNextState();
            
            std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
        }
        
        BoardActionsUtils::TurnPlayerInfo turnInfo;
        machine.getCurTurnPlayerInfo(&turnInfo);
        TEST_EQUAL(turnInfo.bCanRaise, true);
        TEST_EQUAL(turnInfo.llMinRaiseStake, 30);
        TEST_EQUAL(turnInfo.llCallStake, 10);
        
    }
    
    {
        ThmDoubleCardEventableStateMachine machine;
        LogThmDoubleEventableStateMachineListener logListener;
        machine.setDoubleCardStmListener(&logListener);
        
        int64_t llSbChip = 10;
        int64_t llBbChip = 20;
        int64_t llPreblindChip = 20;
        
        int publicCards[5] = {0,1,2,3,4};
        enum { nPlayerCount = 2 };
        int64_t arrPlayerChips[nPlayerCount] = {2000, 2000};
        int arrPlayerHoleCards[nPlayerCount][3] = {
            {0, 5,6},
            {1, 7,8},
        };
        
        machine.start(llSbChip, llBbChip, llPreblindChip,
                      publicCards,
                      arrPlayerChips,
                      arrPlayerHoleCards,
                      nPlayerCount);
        
        while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
            machine.gotoNextState();
            
            std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
        }
        
        BoardActionsUtils::TurnPlayerInfo turnInfo;
        machine.getCurTurnPlayerInfo(&turnInfo);
        TEST_EQUAL(turnInfo.bCanRaise, true);
        TEST_EQUAL(turnInfo.llMinRaiseStake, 30);
        TEST_EQUAL(turnInfo.llCallStake, 10);
        TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, 70));
        
        
        machine.gotoNextState();
        machine.getCurTurnPlayerInfo(&turnInfo);
        TEST_EQUAL(turnInfo.bCanRaise, true);
        TEST_EQUAL(turnInfo.llMinRaiseStake, 120);
        TEST_EQUAL(turnInfo.llCallStake, 60);
        
        
    }

    return true;
}

bool testDispatchPotAlgo() {
    {
        std::map<int, int64_t> mapPlayerBeginChip;
        mapPlayerBeginChip[0] = 300;
        mapPlayerBeginChip[1] = 500;
        
        // 给第一个人
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(false, 200);
        mapPlayerStakes[1] = std::make_pair(false, 400);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 1);
        
        std::map<int, int64_t> mapShowdownPlayers;
        mapShowdownPlayers[0] = 1;
        std::vector<int> leavePlayers = {1};
        BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChip, leavePlayers, &dispatchResult);
        TEST_EXPR(dispatchResult.llTotalChip == 600);
        TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
        TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 500);
        TEST_EXPR(dispatchResult.mapPlayerStakes[1] == 100);
        
        // clear
        mapShowdownPlayers.clear();
        leavePlayers = {1};
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChip, leavePlayers, &dispatchResult);
        TEST_EXPR(dispatchResult.llTotalChip == 600);
        TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
        TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 500);
        TEST_EXPR(dispatchResult.mapPlayerStakes[1] == 100);
        
        // clear
        mapShowdownPlayers.clear();
        leavePlayers = {0, 1};
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChip, leavePlayers, &dispatchResult);
        TEST_EXPR(dispatchResult.llTotalChip == 600);
        TEST_EXPR(dispatchResult.mapPlayerStakes.size()==1);
        TEST_EXPR(dispatchResult.mapPlayerStakes[1] == 600);
    }
    
    {
        std::map<int, int64_t> mapPlayerBeginChip;
        mapPlayerBeginChip[0] = 400;
        mapPlayerBeginChip[1] = 600;
        mapPlayerBeginChip[1] = 800;
        // call
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(true, 200);
        mapPlayerStakes[1] = std::make_pair(true, 600);
        mapPlayerStakes[2] = std::make_pair(false, 600);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 2);
        
        std::map<int, int64_t> mapShowdownPlayers;
        mapShowdownPlayers[0] = 1;
        std::vector<int> leavePlayers = {2};
        BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChip, leavePlayers, &dispatchResult);
        TEST_EXPR(dispatchResult.llTotalChip == 1400);
        TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
        TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 600);
        TEST_EXPR(dispatchResult.mapPlayerStakes[1] == 800);
    }
    
    
    {
        std::map <int, int64_t> mapPlayerBeginChips;
        mapPlayerBeginChips[0] = 400;
        mapPlayerBeginChips[1] = 600;
        mapPlayerBeginChips[2] = 1000;
        
        // leave
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(false, 200);
        mapPlayerStakes[1] = std::make_pair(true, 600);
        mapPlayerStakes[2] = std::make_pair(false, 600);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 1);
        
        {
            std::map<int, int64_t> mapShowdownPlayers;
            mapShowdownPlayers[0] = 1;
            BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
            
            std::vector<int> leavePlayers = {1,2};
            potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
            TEST_EXPR(dispatchResult.llTotalChip == 1400);
            TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
            TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 1000);
            TEST_EXPR(dispatchResult.mapPlayerStakes[2] == 400);
        }
        {
            std::map<int, int64_t> mapShowdownPlayers;
            mapShowdownPlayers[0] = 0;
            BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
            
            std::vector<int> leavePlayers;
            leavePlayers.push_back(1);
            potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
            TEST_EXPR(dispatchResult.llTotalChip == 1400);
            TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
            TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 1000);
            TEST_EXPR(dispatchResult.mapPlayerStakes[2] == 400);
        }
        {
            std::map<int, int64_t> mapShowdownPlayers;
            mapShowdownPlayers[0] = 0;
            BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
            
            std::vector<int> leavePlayers;
            leavePlayers.push_back(2);
            potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
            TEST_EXPR(dispatchResult.llTotalChip == 1400);
            TEST_EXPR(dispatchResult.mapPlayerStakes.size()==2);
            TEST_EXPR(dispatchResult.mapPlayerStakes[0] == 1000);
            TEST_EXPR(dispatchResult.mapPlayerStakes[1] == 400);
        }
    }
    
    {
        std::map<int, int64_t> mapPlayerBeginChips;
        mapPlayerBeginChips[0] = 10;
        mapPlayerBeginChips[1] = 3;
        mapPlayerBeginChips[2] = 10;
        mapPlayerBeginChips[3] = 100;
        
        
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(false, 1);
        mapPlayerStakes[1] = std::make_pair(false, 2);
        mapPlayerStakes[2] = std::make_pair(false, 2);
        mapPlayerStakes[3] = std::make_pair(false, 10);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 1);
        TEST_EQUAL(potReulst.mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.llTotalChip, 15);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].llTotalChip, 15);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(0), 1);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(1), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(2), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(3), 10);
        
        std::vector<int> leavePlayers = {0,2,3};
        std::map<int, int64_t> mapShowdownPlayers;
        mapShowdownPlayers[1] = 1;
        BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
        TEST_EQUAL(dispatchResult.llTotalChip,15);
        TEST_EQUAL(dispatchResult.mapPlayerStakes.size(),2);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[1], 8);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[3], 7);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos.size(), 1);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].llTotalChip, 15);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 2);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.at(1), 8);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.at(3), 7);
    }
    {
        std::map<int, int64_t> mapPlayerBeginChips;
        mapPlayerBeginChips[0] = 10;
        mapPlayerBeginChips[1] = 10;
        mapPlayerBeginChips[2] = 10;
        mapPlayerBeginChips[3] = 100;
        
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(true, 8);
        mapPlayerStakes[1] = std::make_pair(false, 2);
        mapPlayerStakes[2] = std::make_pair(false, 2);
        mapPlayerStakes[3] = std::make_pair(false, 10);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 2);
        TEST_EQUAL(potReulst.mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.llTotalChip, 22);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].llTotalChip, 20);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(0), 8);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(1), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(2), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(3), 8);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[1].llTotalChip, 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[1].mapPlayerStakes.size(), 1);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[1].mapPlayerStakes.at(3), 2);

        
        std::vector<int> leavePlayers = {2,4};
        std::map<int, int64_t> mapShowdownPlayers;
        mapShowdownPlayers[0] = 1;
        BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
        TEST_EQUAL(dispatchResult.llTotalChip,22);
        TEST_EQUAL(dispatchResult.mapPlayerStakes.size(),2);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[0], 20);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[3], 2);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos.size(), 2);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].llTotalChip, 20);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 1);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.at(0), 20);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[1].llTotalChip, 2);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[1].mapPlayerStakes.size(), 1);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[1].mapPlayerStakes.at(3), 2);
    }
    {
        std::map<int, int64_t> mapPlayerBeginChips;
        mapPlayerBeginChips[0] = 2;
        mapPlayerBeginChips[1] = 3;
        mapPlayerBeginChips[2] = 10;
        mapPlayerBeginChips[3] = 100;
        
        BoardPotCollectAlgo::BoardRoundPotResult potReulst;
        std::map<int, std::pair<bool, int64_t> > mapPlayerStakes;
        mapPlayerStakes[0] = std::make_pair(false, 1);
        mapPlayerStakes[1] = std::make_pair(false, 2);
        mapPlayerStakes[2] = std::make_pair(false, 2);
        mapPlayerStakes[3] = std::make_pair(false, 10);
        potReulst.calcFromPlayerStakes(mapPlayerStakes);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos.size(), 1);
        TEST_EQUAL(potReulst.mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.llTotalChip, 15);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].llTotalChip, 15);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 4);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(0), 1);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(1), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(2), 2);
        TEST_EQUAL(potReulst.vecAllPotTotalInfos[0].mapPlayerStakes.at(3), 10);

                std::vector<int> leavePlayers = {1,3,2};
        std::map<int, int64_t> mapShowdownPlayers;
        mapShowdownPlayers[0] = 1;
        BoardPotCollectAlgo::BoardRoundPotResult dispatchResult;
        potReulst.dispatchPot(mapShowdownPlayers, mapPlayerBeginChips, leavePlayers, &dispatchResult);
        TEST_EQUAL(dispatchResult.llTotalChip,15);
        TEST_EQUAL(dispatchResult.mapPlayerStakes.size(),2);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[0], 7);
        TEST_EQUAL(dispatchResult.mapPlayerStakes[2], 8);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos.size(), 1);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].llTotalChip, 15);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes.size(), 2);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes[0], 7);
        TEST_EQUAL(dispatchResult.vecAllPotTotalInfos[0].mapPlayerStakes[2], 8);
    }
    return true;
}

bool testDivideEquallyByPlayerChip() {
    {
        // 0 level
        BoardPotCollectAlgo::BoardOnePotInfo potInfo;
        potInfo.llTotalChip = 0;
        std::vector<BoardPotCollectAlgo::BoardOnePotInfo> vecResult;
        potInfo.divideEquallyByPlayerChip(&vecResult);
        TEST_EXPR(vecResult.size()==01);
    }
    {
        // 1level
        BoardPotCollectAlgo::BoardOnePotInfo potInfo;
        potInfo.llTotalChip = 80;
        potInfo.mapPlayerStakes[0] = 40;
        potInfo.mapPlayerStakes[1] = 40;
        std::vector<BoardPotCollectAlgo::BoardOnePotInfo> vecResult;
        potInfo.divideEquallyByPlayerChip(&vecResult);
        TEST_EXPR(vecResult.size()==1);
        TEST_EXPR(vecResult[0].llTotalChip == 80);
        TEST_EXPR(vecResult[0].mapPlayerStakes.size() == 2);
        TEST_EXPR(vecResult[0].mapPlayerStakes.at(0)==40);
        TEST_EXPR(vecResult[0].mapPlayerStakes.at(1)==40);
    }
    { // 2 levels
        BoardPotCollectAlgo::BoardOnePotInfo potInfo;
        potInfo.llTotalChip = 100;
        potInfo.mapPlayerStakes[0] = 40;
        potInfo.mapPlayerStakes[1] = 20;
        potInfo.mapPlayerStakes[2] = 40;
        
        std::vector<BoardPotCollectAlgo::BoardOnePotInfo> vecResult;
        potInfo.divideEquallyByPlayerChip(&vecResult);
        TEST_EXPR(vecResult.size()==2);
        TEST_EXPR(vecResult[0].llTotalChip == 60);
        TEST_EXPR(vecResult[0].mapPlayerStakes.size() == 3);
        TEST_EXPR(vecResult[0].mapPlayerStakes.at(0)==20);
        TEST_EXPR(vecResult[0].mapPlayerStakes.at(1)==20);
        TEST_EXPR(vecResult[0].mapPlayerStakes.at(2)==20);
        TEST_EXPR(vecResult[1].llTotalChip == 40);
        TEST_EXPR(vecResult[1].mapPlayerStakes.size() == 2);
        TEST_EXPR(vecResult[1].mapPlayerStakes.at(0)==20);
        TEST_EXPR(vecResult[1].mapPlayerStakes.at(2)==20);
    }
    
    return true;
}

bool testStandAndInningEndDispatchPotAlgo(){
    // todo
    return true;
}

bool testOverflowRaiseAndLeave() {
    
    ThmEventableStateMachine machine;
    LogThmEventableStateMachineListener logListener;
    machine.setListener(&logListener);
    
    int64_t llSbChip = 10;
    int64_t llBbChip = 20;
    int64_t llPreblindChip = 0;
    
    int publicCards[5] = {0,1,2,3,4};
    enum { nPlayerCount = 2 };
    int64_t arrPlayerChips[nPlayerCount] = {2000, 200};
    int arrPlayerHoleCards[nPlayerCount][3] = {
        {0, 5,6},
        {1, 7,8},
    };
    
    machine.start(llSbChip, llBbChip, llPreblindChip,
                  publicCards,
                  arrPlayerChips,
                  arrPlayerHoleCards,
                  nPlayerCount);
    
    while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    
    while (machine.hasNextState()){
        if (machine.getCurStateType() == ThmStateType_TurnPlayer)
            break;
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    /*
     
     0:10, 1:20
     
     0:190(raise) -> 200
     0:逃跑

     分彩池结果：
     1: 220
     
     */
    
    // 2:2
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    
    BoardActionsUtils::TurnPlayerInfo turnInfo;
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 0);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==10);
    TEST_EXPR(turnInfo.llMaxStake == 190);
    TEST_EQUAL(turnInfo.llMinRaiseStake, 30);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, 190));
    
    TEST_EXPR(machine.postEventPlayerLeave(0));
    TEST_EXPR(machine.getActTurnCalcator()->isInningNeedEnd());

    while (machine.hasNextState()) {
        machine.gotoNextState();
        if (machine.getCurStateType() == EN_ThmStateType::ThmStateType_DispatchPot)
            break;
    }
    TEST_EXPR(machine.getCurStateType() == EN_ThmStateType::ThmStateType_DispatchPot);
    const BoardPotCollectAlgo::BoardRoundPotResult* pfPot = machine.getPotResultForRound(0);
    TEST_EXPR(pfPot->llTotalChip == 220);
    TEST_EXPR(pfPot->mapPlayerStakes.size() == 2);
    TEST_EXPR(pfPot->mapPlayerStakes.at(0)==200);
    TEST_EXPR(pfPot->mapPlayerStakes.at(1)==20);
    TEST_EXPR(pfPot->vecAllPotTotalInfos.size() == 1);
    TEST_EXPR(pfPot->vecAllPotTotalInfos.at(0).llTotalChip == 220);
    TEST_EXPR(pfPot->vecAllPotTotalInfos.at(0).mapPlayerStakes.size()==2);
    TEST_EXPR(pfPot->vecAllPotTotalInfos.at(0).mapPlayerStakes.at(0)==200);
    TEST_EXPR(pfPot->vecAllPotTotalInfos.at(0).mapPlayerStakes.at(1)==20);
    
    const BoardPotCollectAlgo::BoardRoundPotResult* potResult = machine.getWinData();
    TEST_EXPR(potResult->llTotalChip == 220);
    TEST_EXPR(potResult->mapPlayerStakes.size() == 1);
    TEST_EQUAL(potResult->mapPlayerStakes.at(1), 220);
    TEST_EXPR(potResult->vecAllPotTotalInfos.size()==1);
    TEST_EXPR(potResult->vecAllPotTotalInfos[0].mapPlayerStakes.size()==1);
    TEST_EXPR(potResult->vecAllPotTotalInfos[0].mapPlayerStakes.at(1)==220);
    
    
    return true;
}

bool testInvalidRaiseToCall_TurnInfo(){
    
    ThmEventableStateMachine machine;
    LogThmEventableStateMachineListener logListener;
    machine.setListener(&logListener);
    
    int64_t llSbChip = 10;
    int64_t llBbChip = 20;
    int64_t llPreblindChip = 0;
    
    int publicCards[5] = {0,1,2,3,4};
    enum { nPlayerCount = 2 };
    int64_t arrPlayerChips[nPlayerCount] = {2000, 2000};
    int arrPlayerHoleCards[nPlayerCount][3] = {
        {0, 5,6},
        {1, 7,8},
    };
    
    machine.start(llSbChip, llBbChip, llPreblindChip,
                  publicCards,
                  arrPlayerChips,
                  arrPlayerHoleCards,
                  nPlayerCount);
    
    while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    
    while (machine.hasNextState()){
        if (machine.getCurStateType() == ThmStateType_TurnPlayer)
            break;
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    /*
     
     0:10, 1:20
     
     0:30(raise) -> 40
     1: canRaise
     
     */
    
    // 2:2
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    
    BoardActionsUtils::TurnPlayerInfo turnInfo;
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 0);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==10);
    TEST_EXPR(turnInfo.llMaxStake == 1990);
    TEST_EXPR(turnInfo.llMinRaiseStake == 30);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, 30));
    
    machine.gotoNextState();
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 1);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llMaxStake == 1980);
    TEST_EQUAL(turnInfo.llMinRaiseStake, 40);
    TEST_EXPR(turnInfo.llCallStake==20);
    
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CALL, 20));
    
    
    // Flop
    while (machine.hasNextState()){
        if (machine.getCurStateType() == ThmStateType_TurnPlayer)
            break;
        machine.gotoNextState();
    }
    
    // 1
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 1);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==0);
    TEST_EXPR(turnInfo.llMaxStake == 1960);
    TEST_EXPR(turnInfo.llMinRaiseStake == 20);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CHECK, 0));
    
    machine.gotoNextState();
    // 0
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 0);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==0);
    TEST_EXPR(turnInfo.llMaxStake == 1960);
    TEST_EXPR(turnInfo.llMinRaiseStake == 20);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CHECK, 0));
    
    // Turn
    while (machine.hasNextState()){
        if (machine.getCurStateType() == ThmStateType_TurnPlayer)
            break;
        machine.gotoNextState();
    }
    
    // 1
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 1);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==0);
    TEST_EXPR(turnInfo.llMaxStake == 1960);
    TEST_EXPR(turnInfo.llMinRaiseStake == 20);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, 40));
    
    machine.gotoNextState();
    // 0
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 0);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake==40);
    TEST_EXPR(turnInfo.llMaxStake == 1960);
    TEST_EXPR(turnInfo.llMinRaiseStake == 80);

    return true;

}
// 测试无效加注
bool testInvalidRaiseToCall(){
    ThmEventableStateMachine machine;
    LogThmEventableStateMachineListener logListener;
    machine.setListener(&logListener);
    
    int64_t llSbChip = 1;
    int64_t llBbChip = 2;
    int64_t llPreblindChip = 0;
    
    int publicCards[5] = {0,1,2,3,4};
    enum { nPlayerCount = 4 };
    int64_t arrPlayerChips[nPlayerCount] = {20, 3, 20, 20};
    int arrPlayerHoleCards[nPlayerCount][3] = {
        {0, 5,6},
        {1, 7,8},
        {2, 9, 10},
        {3, 11, 12},
    };
    
    machine.start(llSbChip, llBbChip, llPreblindChip,
                  publicCards,
                  arrPlayerChips,
                  arrPlayerHoleCards,
                  nPlayerCount);
    
    while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    /*
     
     [20,3, 20,20]
     0:1, 1:2
     
     2:2 -> 3:2 ->0:2 （call 1）-> 1:3（raise 1） -> 2: call -> 3: call 0: call
     
     */
    
    // 2:2
    
    while (machine.hasNextState()){
        if (machine.getCurStateType() == ThmStateType_TurnPlayer)
            break;
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    
    BoardActionsUtils::TurnPlayerInfo turnInfo;
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 2);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llMaxStake == 20);
    TEST_EXPR(turnInfo.llMinRaiseStake == 4);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CALL, 2));
    
    machine.gotoNextState();
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 3);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llMaxStake == 20);
    TEST_EXPR(turnInfo.llMinRaiseStake == 4);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CALL, 2));
    
    machine.gotoNextState();
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 0);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llMaxStake == 19);
    TEST_EXPR(turnInfo.llMinRaiseStake == 3);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_CALL, 1));
    
    
    machine.gotoNextState();
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 1);
    TEST_EXPR(turnInfo.bCanRaise);
    TEST_EXPR(machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, 1));
    
    
    machine.gotoNextState();
    TEST_EXPR(machine.getCurStateType() == ThmStateType_TurnPlayer);
    machine.getCurTurnPlayerInfo(&turnInfo);
    std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
    TEST_EXPR(turnInfo.nPos == 2);
    TEST_EXPR(!turnInfo.bCanRaise);
    TEST_EXPR(turnInfo.llCallStake == 1);

    return true;
}

/**
 *  测试双人玩家双飞
 *
 *  @return
 */
bool testAllinLeavePlayer() {
    ThmEventableStateMachine machine;
    LogThmEventableStateMachineListener logListener;
    machine.setListener(&logListener);
    
    int64_t llSbChip = 1;
    int64_t llBbChip = 2;
    int64_t llPreblindChip = 0;
    
    int publicCards[5] = {0,1,2,3,4};
    enum { nPlayerCount = 2 };
    int64_t arrPlayerChips[nPlayerCount] = {200, 200};
    int arrPlayerHoleCards[nPlayerCount][3] = {
        {0, 5,6},
        {1, 7,8},
    };
    
    machine.start(llSbChip, llBbChip, llPreblindChip,
                  publicCards,
                  arrPlayerChips,
                  arrPlayerHoleCards,
                  nPlayerCount);
    
    while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    bool bStateTriggled = false;
    
    while (machine.hasNextState()){
        
        switch (machine.getCurStateType()) {
            case ThmStateType_TurnPlayer:
            {
                BoardActionsUtils::TurnPlayerInfo turnInfo;
                machine.getCurTurnPlayerInfo(&turnInfo);
                if (bStateTriggled){
                    
                    std::cout << "不应该的状态 轮到了玩家 = " << turnInfo.nPos << std::endl;
                    return false;
                }
                
                bStateTriggled = true;
                std::cout << "轮到了玩家 = " << turnInfo.nPos << std::endl;
                machine.postEventPlayerAct(turnInfo.nPos, ACT_RAISE, turnInfo.llMaxStake);
                
                std::cout << "发送一个玩家离开 " << std::endl;
                machine.postEventPlayerLeave(turnInfo.nPos);
            }
                break;
            default:
                break;
        }
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    int64_t chip1 = 0;
    int64_t chip2 = 1;
    machine.iterateAllPlayers([&](const ThmEventableStateMachine::GamePlayer * player, int index, bool *){
        if (index==0) chip1 = player->m_llInningEndChip;
        else if (index==1) chip2 = player->m_llInningEndChip;
        
        std::cout << " player " << index <<  " chip = " << player->m_llInningEndChip << std::endl;
    });
    
    // 筹码
    TEST_EXPR((chip1 + chip2) == 400);
    return true;
}

/**
 *  测试双人玩家双飞
 *
 *  @return
 */
bool testDoublePlayerLeave() {
    ThmEventableStateMachine machine;
    LogThmEventableStateMachineListener logListener;
    machine.setListener(&logListener);
    
    int64_t llSbChip = 1;
    int64_t llBbChip = 2;
    int64_t llPreblindChip = 0;
    
    int publicCards[5] = {0,1,2,3,4};
    enum { nPlayerCount = 2 };
    int64_t arrPlayerChips[nPlayerCount] = {200, 200};
    int arrPlayerHoleCards[nPlayerCount][3] = {
        {0, 5,6},
        {1, 7,8},
    };
    
    machine.start(llSbChip, llBbChip, llPreblindChip,
               publicCards,
               arrPlayerChips,
               arrPlayerHoleCards,
               nPlayerCount);
    
    while (machine.getCurStateType() != EN_ThmStateType::ThmStateType_TurnPlayer) {
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    std::cout << "发送一个玩家离开 " << std::endl;
    machine.postEventPlayerLeave(0);
    std::cout << "发送另一个玩家离开 " << std::endl;
    machine.postEventPlayerLeave(1);
    while (machine.hasNextState()){
        
        switch (machine.getCurStateType()) {
            case ThmStateType_TurnPlayer:
            {
                BoardActionsUtils::TurnPlayerInfo turnInfo;
                machine.getCurTurnPlayerInfo(&turnInfo);
                std::cout << "不应该的状态 轮到了玩家 = " << turnInfo.nPos << std::endl;
                return false;
            }
                break;
            default:
                break;
        }
        machine.gotoNextState();
        
        std::cout << " curType = " << thmStateToString(machine.getCurStateType()) << std::endl;
    }
    
    
    int64_t chip1 = 0;
    int64_t chip2 = 1;
    machine.iterateAllPlayers([&](const ThmEventableStateMachine::GamePlayer * player, int index, bool *){
        if (index==0) chip1 = player->m_llInningEndChip;
        else if (index==1) chip2 = player->m_llInningEndChip;
        
        std::cout << " player " << index <<  " chip = " << player->m_llInningEndChip << std::endl;
    });

    // 筹码
    TEST_EXPR((chip1 + chip2) == 400);
    return true;
}
